﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Alma.Core
{
    public static class SearchParser
    {
        /*
        public static SearchExpression ParseWord(List<string> tokens)
        {
            var r = new SearchWord() { Value = tokens[0] };
            tokens.RemoveAt(0);
            return r;
        }
        */
        public static SearchExpression ParseSelector(List<string> tokens)
        {
            if (tokens.Count < 1)
                throw new SearchException("Requête incomplète");
            var first = tokens[0];
            tokens.RemoveAt(0);
            if (tokens.Count < 2 || tokens[0] != ":")
                return new SearchWord() { Value = first };
            tokens.RemoveAt(0);
            var second = tokens[0];
            tokens.RemoveAt(0);
            var s = new SearchSelector() { Selector = first, Value = second };
            //if (tokens.Count < 2 || tokens[0] != "=")
            //    return s;
            //s.Operator = tokens[0];
            //tokens.RemoveAt(0);
            //s.Operand = tokens[0];
            //tokens.RemoveAt(0);
            return s;
        }

        public static SearchExpression ParseCriterion(List<string> tokens)
        {
            if (tokens.Count < 4)
                return ParseSelector(tokens);
            if (tokens[0] != "@")
                return ParseSelector(tokens);
            tokens.RemoveAt(0);
            var criterion = new SearchCriterion() {Criterion = tokens[0]};
            tokens.RemoveAt(0);
            criterion.Operator = tokens[0];
            tokens.RemoveAt(0);
            criterion.Value = tokens[0];
            tokens.RemoveAt(0);
            return criterion;
        }

        public static SearchExpression ParseParenthesis(List<string> tokens)
        {
            if (tokens.Count < 3)
                return ParseCriterion(tokens);
            if (tokens[0] != "(")
                return ParseCriterion(tokens);
            tokens.RemoveAt(0);
            var exp = ParseOr(tokens);
            if (tokens.Count < 1 || tokens[0] != ")")
                throw new SearchException("Il manque une parenthèse droite ')'.");
            tokens.RemoveAt(0);
            return exp;
        }

        public static SearchExpression ParseNot(List<string> tokens)
        {
            if (tokens.Count < 2)
                return ParseParenthesis(tokens);
            if (tokens[0] != "-")
                return ParseParenthesis(tokens);
            tokens.RemoveAt(0);
            return new SearchNot() { Inner = ParseNot(tokens) };
        }

        public static SearchExpression ParseAnd(List<string> tokens)
        {
            var first = ParseNot(tokens);
            if (tokens.Count < 1)
                return first;
            if (tokens[0] != "+" && (!char.IsLetterOrDigit(tokens[0][0]) &&
                tokens[0] != "-" && tokens[0] != "(" && tokens[0] != "@"))
                return first;
            if (tokens[0] == "+")
                tokens.RemoveAt(0);
            return new SearchAnd { Left = first, Right = ParseAnd(tokens) };
        }

        public static SearchExpression ParseOr(List<string> tokens)
        {
            var first = ParseAnd(tokens);
            if (tokens.Count < 2)
                return first;
            if (tokens[0] != "|")
                return first;
            tokens.RemoveAt(0);
            return new SearchOr { Left = first, Right = ParseOr(tokens) };
        }

        public static SearchExpression ParseRequest(List<string> tokens)
        {
            var exp = ParseOr(tokens);
            if (tokens.Count == 0)
                return new SearchRequest() { Expression = exp };
            if (tokens[0] == ")")
                throw new SearchException("Il manque une parenthèse gauche '('.");
            throw new SearchException("Requête erronée.");
        }


    }
}